<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>对象属性的控制</title>
    <!-- 
  在JavaScript中，对象属性的控制涉及到如何定义、访问、修改和删除对象的属性。JavaScript提供了多种方式来控制对象属性的行为，包括使用属性描述符、访问器属性和控制属性的可枚举性、可写性和可配置性。
  一、对象属性的基本概念
  - 属性：对象的属性是由键（字符串或符号）和对应的值（可以是任何数据类型）组成的。
  - 属性类型：属性可以是数据属性或访问器属性。

  二、数据属性与访问器属性
  1. 数据属性：
    - 包含值和一些描述符（如可写性、可枚举性、可配置性）。
      const obj = {
        name: "Alice",
        age: 25
    };
  2. 访问器属性：
    - 通过 getter 和 setter 方法来定义，允许在访问属性时执行特定的逻辑。
    const person = {
        firstName: "John",
        lastName: "Doe",
        get fullName() {
            return `${this.firstName} ${this.lastName}`;
        },
        set fullName(name) {
            [this.firstName, this.lastName] = name.split(" ");
        }
    };

    console.log(person.fullName); // 输出: John Doe
    person.fullName = "Jane Smith";
    console.log(person.firstName); // 输出: Jane
  三、属性描述符
  JavaScript中的每个属性都可以有一个描述符，描述符分为数据描述符和访问器描述符。
  1. 数据描述符：
    - 包含以下属性：
      -  `value` ：属性的值。
      -  `writable` ：布尔值，指示属性是否可写。
      -  `enumerable` ：布尔值，指示属性是否可枚举（即在  `for...in`  循环中可见）。
      -  `configurable` ：布尔值，指示属性是否可配置（即是否可以删除或修改其属性描述符）。

  2. 访问器描述符：
    - 包含以下属性：
      -  `get` ：获取属性值的函数。
      -  `set` ：设置属性值的函数。
      -  `enumerable` ：布尔值，指示属性是否可枚举。
      -  `configurable` ：布尔值，指示属性是否可配置。

  四、定义和修改属性
  可以使用  `Object.defineProperty()`  方法来定义或修改对象的属性描述符。
  const obj = {};

  Object.defineProperty(obj, 'name', {
      value: 'Alice',
      writable: false, // 不可写
      enumerable: true, // 可枚举
      configurable: false // 不可配置
  });

  console.log(obj.name); // 输出: Alice
  obj.name = 'Bob'; // 无效操作，不会改变值
  console.log(obj.name); // 仍然输出: Alice

  五、控制属性的可枚举性
  - 使用  `Object.keys()`  方法可以获取对象可枚举的属性。
  - 使用  `Object.getOwnPropertyNames()`  方法可以获取对象所有属性（包括不可枚举的）。

  六、删除属性
  使用  `delete`  操作符可以删除对象的属性，但前提是该属性的  `configurable`  属性必须为  `true` 。
  const obj = {
      name: "Alice"
  };

  delete obj.name; // 删除属性
  console.log(obj.name); // 输出: undefined

  七、总结
  - JavaScript对象的属性控制涉及到如何定义、访问、修改和删除属性。
  - 数据属性和访问器属性提供了不同的方式来管理属性。
  - 属性描述符允许开发者控制属性的可写性、可枚举性和可配置性。
  - 使用  `Object.defineProperty()`  方法可以精确地控制属性的行为。
   -->
  </head>
  <body>
    <script>
      // 1. 定义属性
      const obj = {
        name: "Alice",
        age: 18,
      };
      Object.defineProperty(obj, "name", {
        value: "Alice",
        writable: true,
        enumerable: true,
        configurable: true,
      });

      // 2. 访问属性
      console.log(obj.name); // 输出: Alice

      // 3. 修改属性
      obj.name = "Bob"; // 修改属性值

      console.log(obj.name); // 输出: Bob

      // 4. 控制属性的可写性
      Object.defineProperty(obj, "name", {
        value: "Alice",
        writable: false, // 不可写
        enumerable: true, // 可枚举
        configurable: true, // 可配置
      });

      obj.name = "Bob"; // 尝试修改属性值
      console.log(obj.name); // 输出: Alice (未修改成功)

      // 5. 控制属性的可枚举性
      console.log(Object.keys(obj)); // 输出: ["name"]

      // 6. 删除属性
      delete obj.name; // 删除属性

      Object.defineProperties(obj, {
        name: {
          value: "Alice",
          writable: true,
          enumerable: true,
          configurable: true,
        },
        age: {
          value: 18,
          writable: true,
          enumerable: true,
          configurable: true,
        },
      });
    </script>
  </body>
</html>
